package pl.edu.mimuw.mas.agent.behaviour.hunting.hunter;

import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pl.edu.mimuw.mas.agent.DogAgent;
import pl.edu.mimuw.mas.agent.HunterAgent;
import pl.edu.mimuw.mas.agent.HuntingAgent;
import pl.edu.mimuw.mas.agent.behaviour.ReplyWaitingBehaviour;
import pl.edu.mimuw.mas.message.ScareFactorMessage;
import pl.edu.mimuw.mas.message.ScareRequestMessage;
import pl.edu.mimuw.mas.util.Time;

public class BestPairChoosingBehaviour extends SequentialBehaviour {

	private static final long serialVersionUID = -4942921075094894212L;
	
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	
	private List<ACLMessage> replies = new ArrayList<ACLMessage>();

	public BestPairChoosingBehaviour(HunterAgent a) {
		super(a);
		
		// ogłaszam swoja parę
		addSubBehaviour(new OneShotBehaviour(a) {

			private static final long serialVersionUID = -7355517923277235986L;

			@Override
			public void action() {
				HunterAgent a = (HunterAgent) myAgent;
				
//				logger.debug("{} : ogłaszam swoją parę", a.getName());
				
				ACLMessage request = new ACLMessage(ACLMessage.INFORM);

				try {
					request.setContentObject(new ScareFactorMessage(a.getAID(), a.getScareFactor()));
					request.setConversationId(HunterAgent.BEST_PAIR_CONV);
				} catch (IOException e) {
					logger.error("{} : błąd podczas serializacji wiadomości", a.getName(), e);
				}

				DFAgentDescription template = new DFAgentDescription();
				// agent jest łowcą
				ServiceDescription sdHunter = new ServiceDescription();
				sdHunter.setType(HunterAgent.HUNTER_SERVICE_TYPE);
				template.addServices(sdHunter);
				// oraz liderem
				ServiceDescription sdLeader = new ServiceDescription();
				sdLeader.setType(HuntingAgent.LEADER_SERVICE_TYPE);
				template.addServices(sdLeader);

				try {
					DFAgentDescription[] results = DFService.search(a, template);
					for (int i = 0; i < results.length; i++) {
						request.addReceiver(results[i].getName());
					}
				} catch (FIPAException e) {
					logger.error("{} : błąd FIPA", a.getName(), e);
				}

				a.send(request);
			}

		});
		
		// czekam na info od innych
		MessageTemplate mt = MessageTemplate.and(
				MessageTemplate.MatchConversationId(HunterAgent.BEST_PAIR_CONV),
				MessageTemplate.MatchPerformative(ACLMessage.INFORM));
		addSubBehaviour(new ReplyWaitingBehaviour(a, mt, Time.MESSAGE_REPLY_WAIT, replies));
		
		// sprawdzam czy mam najlepszy wspolczynnik straszenia
		addSubBehaviour(new OneShotBehaviour(a) {

			private static final long serialVersionUID = 7542517422510445729L;

			@Override
			public void action() {
				HunterAgent a = (HunterAgent) myAgent;
				
//				logger.debug("{} : wybieram najlepszą parę", a.getName());
				
				ScareFactorMessage sm;
				boolean isActive = true;
				for (ACLMessage reply : replies) {
					try {
						sm = (ScareFactorMessage) reply.getContentObject();
						if (sm.scareFactor > a.getScareFactor()) {
							isActive = false;
						}
					} catch (UnreadableException e) {
						logger.error("{} : UnreadableException {}", a.getName(), e);
					}
				}
				if (isActive) {
					logger.debug("{} : odebralem info od {} par i jestem najlepszy!!!",
							a.getName(), replies.size());
					// aktywuję łowcę
					a.activate();
					// aktywuję psa
					activateDog();
				}
			}
			
			private void activateDog() {
				HunterAgent a = (HunterAgent) myAgent;
				ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
				msg.setConversationId(DogAgent.SCARE_CONV);
				msg.addReceiver(a.getPairedLeader());
				try {
					msg.setContentObject(new ScareRequestMessage(a.getAID(), a.getAvgGroupPosition()));
				} catch (IOException e) {
					logger.error("{} : błąd podczas ustawiania treści wiadomośc", a.getName());
				}
				a.send(msg);
			}
			
		});
	}

}
